Avastage ReactDOM'iga Reacti DOM-i interaktsiooni tuuma. Õppige kliendipoolset renderdamist, portaale ja avage globaalsed jõudlus- ning SEO-eelised serveripoolse renderdamisega (SSR).
Reacti võimsuse avamine: sügav sukeldumine ReactDOM-i ja serveripoolsesse renderdamisse
Reacti laias ökosüsteemis keskendume sageli komponentidele, olekule ja haakidele (hooks). Kuid maagia, mis muudab meie deklaratiivsed komponendid veebibrauseris käegakatsutavateks ja interaktiivseteks kasutajaliidesteks, toimub läbi üliolulise teegi: react-dom. See pakett on hädavajalik sild Reacti abstraktse virtuaalse DOM-i ja konkreetse dokumendiobjekti mudeli (DOM) vahel, mida kasutajad näevad ja millega suhtlevad. Arendajatele, kes loovad rakendusi globaalsele publikule, on react-dom'i tõhusa kasutamise mõistmine võtmetähtsusega, et luua suure jõudlusega, ligipääsetavaid ja otsingumootorisõbralikke kogemusi.
See põhjalik juhend viib teid sügavale react-dom teeki. Alustame kliendipoolse renderdamise põhitõdedest, uurime võimsaid utiliite nagu portaalid ja seejärel nihutame fookuse serveripoolse renderdamise (SSR) transformatiivsele paradigmale ning selle mõjule jõudlusele ja SEO-le kogu maailmas.
Kliendipoolse renderdamise (CSR) tuum ReactDOM-iga
Oma olemuselt töötab React abstraktsiooni põhimõttel. Me kirjeldame, mida kasutajaliides peaks antud oleku puhul välja nägema, ja React tegeleb sellega, kuidas see saavutada. Kliendipoolse renderdamise (CSR) mudel, mis on vaikimisi kasutusel selliste tööriistadega nagu Create React App loodud rakendustes, järgib selget protsessi:
- Brauser kĂĽsib veebilehte ja saab minimaalse HTML-faili lingiga suurele JavaScripti paketile.
- Brauser laadib alla ja käivitab JavaScripti paketi.
- React võtab juhtimise üle, ehitab mällu virtuaalse DOM-i ja kasutab seejärel
react-dom'i, et renderdada kogu rakendus kindlasse DOM-elementi (tavaliselt<div id="root"></div>). - Kasutaja saab nüüd rakendust näha ja sellega suhelda.
Seda protsessi juhib kaasaegsetes Reacti rakendustes üksainus võimas sisenemispunkt.
Kaasaegne API: `ReactDOM.createRoot()`
Kui olete Reactiga mõned aastad töötanud, olete tõenäoliselt tuttav ReactDOM.render()'iga. Kuid React 18 väljalaskega on ametlik ja soovitatav viis kliendipoolselt renderdatud rakenduse lähtestamiseks kasutada ReactDOM.createRoot().
Miks selline muudatus? Uus juure API võimaldab Reacti konkurentseid funktsioone, mis lubavad Reactil ette valmistada mitu kasutajaliidese versiooni korraga. See on aluseks võimsatele jõudluse täiustustele ja uutele funktsioonidele nagu üleminekud (transitions). Pärandatud ReactDOM.render()'i kasutamine jätab teie rakenduse nendest kaasaegsetest võimalustest ilma.
Nii lähtestatakse tüüpiline Reacti rakendus:
// index.js - Teie rakenduse sisenemispunkt
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
// 1. Leidke DOM-element, kuhu Reacti rakendus paigaldatakse.
const rootElement = document.getElementById('root');
// 2. Looge selle elemendi jaoks juur.
const root = ReactDOM.createRoot(rootElement);
// 3. Renderdage oma peamine App-komponent juure sisse.
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
See lihtne ja elegantne koodiplokk on peaaegu iga kliendipoolse Reacti rakenduse aluseks. Meetodit root.render() saab kasutajaliidese uuendamiseks mitu korda kutsuda; React haldab uuendusi tõhusalt, võrreldes uut virtuaalset DOM-i puud eelmisega ja rakendades tegelikule DOM-ile ainult vajalikud muudatused.
Põhitõdedest kaugemale: olulised ReactDOM-i utiliidid
Kuigi createRoot on peamine sisenemispunkt, pakub react-dom mitmeid teisi võimsaid utiliite tavaliste, kuid keerukate kasutajaliidese väljakutsete lahendamiseks.
Kastist välja murdmine: `createPortal`
Kas olete kunagi proovinud luua modaalakent, tööriistavihjet (tooltip) või teavitusakent ja sattunud probleemidesse CSS-i virnastamise konteksti (z-index) või esivanema overflow: hidden omadusest tuleneva kärpimisega? See on klassikaline kasutajaliidese probleem. Komponendi loogika seisukohast võib modaalaken kuuluda sügaval teie komponendipuus asuvale nupule. Kuid visuaalselt peab see olema renderdatud DOM-i ülemisel tasemel, sageli otse <body> lapselemendina, et vältida neid CSS-i piiranguid.
Just seda probleemi lahendab ReactDOM.createPortal. See võimaldab teil renderdada komponendi laps-elemente teise DOM-i ossa, väljaspool selle vanema DOM-i hierarhiat, säilitades samal ajal selle positsiooni Reacti komponendipuus. See tähendab, et sündmuste levimine (event bubbling) töötab endiselt ootuspäraselt – portaali seest käivitatud sündmus levib üles oma esivanemateni Reacti puus, isegi kui need esivanemad ei ole selle otsesed vanemad DOM-is.
Näide: korduvkasutatav modaalakna komponent
// Modal.js
import React from 'react';
import ReactDOM from 'react-dom';
// Eeldame, et teie public/index.html failis on <div id="modal-root"></div>
const modalRoot = document.getElementById('modal-root');
const Modal = ({ children }) => {
const el = document.createElement('div');
React.useEffect(() => {
// Paigaldamisel lisage element modaalakna juurele.
modalRoot.appendChild(el);
// Eemaldamisel puhastage, eemaldades elemendi.
return () => {
modalRoot.removeChild(el);
};
}, [el]);
// Kasutage createPortal'i, et renderdada laps-elemendid eraldi DOM-sõlme.
return ReactDOM.createPortal(children, el);
};
export default Modal;
// App.js
import React, { useState } from 'react';
import Modal from './Modal';
function App() {
const [showModal, setShowModal] = useState(false);
return (
<div>
<h1>Minu rakendus</h1>
<button onClick={() => setShowModal(true)}>Näita modaalakent</button>
{showModal && (
<Modal>
<div className="modal-content">
<h2>See on portaali modaalaken!</h2>
<p>See on renderdatud '#modal-root' sisse, kuid selle olekut haldab App.js</p>
<button onClick={() => setShowModal(false)}>Sulge</button>
</div>
</Modal>
)}
</div>
);
}
SĂĽnkroonsete uuenduste sundimine: `flushSync`
React on jõudluse osas uskumatult tark. Üks selle peamisi optimeerimisi on olekuuuenduste pakendamine (state batching). Kui kutsute ühes sündmusekäsitlejas (event handler) mitu olekuuuendusfunktsiooni, ei renderda React kohe pärast igaüht uuesti. Selle asemel pakendab see need kokku ja teeb lõpus üheainsa tõhusa uuestirenderdamise. See hoiab ära tarbetuid vahepealseid renderdusi.
Siiski on haruldasi erijuhte, kus peate sundima Reacti DOM-i uuendusi rakendama sünkroonselt. Näiteks võib teil olla vaja lugeda DOM-elemendi suurust või asukohta kohe pärast olekumuutust, mis seda mõjutab. Siin tulebki appi flushSync.
flushSync on pääsetee. Määratlete sellega olekuuuenduse ja React käivitab uuenduse sünkroonselt ning kirjutab muudatused DOM-i enne mis tahes järgneva koodi käivitamist.
Kasutage seda ettevaatlikult! flushSync'i liigne kasutamine võib tühistada pakendamise jõudluseelised. Tavaliselt on seda vaja ainult koostalitlusvõimeks kolmandate osapoolte teekidega või keerukate animatsioonide ja paigutusloogika jaoks.
import { flushSync } from 'react-dom';
function ListComponent() {
const [items, setItems] = useState(['A', 'B', 'C']);
const listRef = React.useRef();
const handleAddItem = () => {
// Oletame, et peame kerima nimekirja lõppu kohe pärast elemendi lisamist.
flushSync(() => {
setItems(prev => [...prev, 'D']);
});
// Selleks ajaks, kui see rida käivitub, on DOM uuendatud. Uus element 'D' on renderdatud.
// Saame nüüd usaldusväärselt mõõta nimekirja uut kõrgust ja kerida.
listRef.current.scrollTop = listRef.current.scrollHeight;
};
return (
<div>
<ul ref={listRef} style={{ height: '100px', overflow: 'auto' }}>
{items.map(item => <li key={item}>{item}</li>)}
</ul>
<button onClick={handleAddItem}>Lisa element ja keri</button>
</div>
);
}
Märkus mineviku kohta: `findDOMNode` (pärand)
Vanemates koodibaasides võite kohata funktsiooni findDOMNode. Seda funktsiooni kasutati klassikomponendi instantsist aluseks oleva brauseri DOM-sõlme saamiseks. Kuid seda peetakse nüüd pärandiks ja selle kasutamine on tungivalt ebasoovitatav.
Peamine põhjus on see, et see rikub komponentide abstraktsiooni. Vanemkomponent ei tohiks DOM-sõlme leidmiseks tungida oma laps-komponendi implementatsiooni detailidesse. See muudab komponendid hapraks ja raskesti refaktoreeritavaks. Lisaks, seoses funktsionaalsete komponentide ja haakide (hooks) esilekerkimisega, findDOMNode nendega üldse ei tööta.
Kaasaegne ja õige lähenemine on kasutada ref'e ja ref'i edastamist (ref forwarding). Laps-komponent saab selgesõnaliselt oma vanemale eksponeerida konkreetse DOM-sõlme forwardRef'i kaudu, säilitades selge ja otsese lepingu.
Paradigmanihe: serveripoolne renderdamine (SSR) ReactDOM-iga
Kuigi CSR on võimas keerukate ja interaktiivsete rakenduste loomiseks, on sellel kaks olulist puudust, eriti globaalse kasutajaskonna jaoks:
- Esialgse laadimise jõudlus: Kasutaja näeb tühja valget ekraani, kuni kogu JavaScripti pakett on alla laaditud, parsitud ja käivitatud. Aeglasemates võrkudes või vähem võimsatel seadmetel, mis on paljudes maailma osades tavalised, võib see põhjustada masendavalt pikka ooteaega.
- Otsingumootoritele optimeerimine (SEO): Kuigi otsingumootorite roomikud on muutunud JavaScripti käivitamisel paremaks, ei ole nad täiuslikud. Server, mis saadab tagasi praktiliselt tühja HTML-faili, tugineb roomikule lehe renderdamisel, mis võib viia mittetäieliku indekseerimiseni või madalamate edetabelikohtadeni võrreldes lehega, mis serveerib algusest peale täielikult vormindatud HTML-sisu.
Serveripoolne renderdamine (SSR) tegeleb nende probleemidega otse. SSR-i puhul toimub teie Reacti rakenduse esmane renderdamine serveris. Server genereerib nõutud lehe jaoks täieliku HTML-koodi ja saadab selle brauserile. Kasutaja näeb sisu kohe – see on tohutu võit tajutava jõudluse ja SEO jaoks.
`react-dom/server` pakett
Selle serveripoolse maagia teostamiseks pakub React eraldi paketi: react-dom/server. See pakett sisaldab tööriistu, mis on vajalikud komponentide renderdamiseks mitte-DOM-keskkonnas, näiteks Node.js serveris.
Kaks peamist meetodit on:
renderToString(element): See on SSR-i tööhobune. See võtab Reacti elemendi (nagu teie<App />komponent) ja renderdab selle staatiliseks HTML-stringiks. See string sisaldab spetsiaalseid `data-reactroot` atribuute, mida React kasutab kliendi poolel protsessis, mida nimetatakse hüdreerimiseks.renderToStaticMarkup(element): See on sarnane, kuid jätab välja täiendavad `data-reactroot` atribuudid. See on kasulik, kui soovite genereerida puhast, staatilist HTML-i, mida kliendi poolel ei hüdreerita. Suurepärane kasutusjuhtum on HTML-i genereerimine e-kirjade mallide jaoks.
Pusle viimane tĂĽkk: hĂĽdreerimine
Serveri genereeritud HTML on lihtsalt staatiline märgistus. See näeb õige välja, kuid see ei ole interaktiivne. Nupud ei tööta ja puudub kliendipoolne olek. Protsessi, mis muudab selle staatilise HTML-i interaktiivseks, nimetatakse hüdreerimiseks.
Pärast seda, kui brauser on serveri renderdatud HTML-i kätte saanud, laadib see alla ka sama JavaScripti paketi nagu CSR-i puhul. Kuid selle asemel, et kogu DOM nullist uuesti luua, võtab React olemasoleva HTML-i üle. See käib läbi serveri renderdatud DOM-puu, lisab vajalikud sündmuste kuulajad (nagu onClick) ja lähtestab rakenduse oleku. See protsess on sujuv ja palju kiirem kui DOM-i nullist ülesehitamine.
HĂĽdreerimise lubamiseks kliendi poolel kasutate createRoot() asemel ReactDOM.hydrateRoot().
Lihtsustatud SSR-voo näide (kasutades serveris Express.js-i):
// server.js
import express from 'express';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import App from './src/App';
const app = express();
app.get('/', (req, res) => {
// 1. Renderdage Reacti App-komponent HTML-stringiks.
const appHtml = ReactDOMServer.renderToString(<App />);
// 2. SĂĽstige renderdatud HTML malli.
const html = `
<!DOCTYPE html>
<html>
<head>
<title>React SSR rakendus</title>
</head>
<body>
<div id="root">${appHtml}</div>
<script src="/client.js"></script> <!-- Kliendipoolne JS-pakett -->
</body>
</html>
`;
// 3. Saatke täielik HTML-dokument kliendile.
res.send(html);
});
app.listen(3000, () => {
console.log('Server kuulab pordil 3000');
});
// client.js - Kliendipoolne sisenemispunkt
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const rootElement = document.getElementById('root');
// 1. createRoot'i asemel kasutage hydrateRoot'i.
// React ei loo DOM-i uuesti, vaid lisab sĂĽndmuste kuulajad
// olemasolevale serveri renderdatud märgistusele.
ReactDOM.hydrateRoot(
rootElement,
<React.StrictMode>
<App />
</React.StrictMode>
);
On ülioluline, et kliendi poolel hüdreerimiseks renderdatud komponendipuu oleks identne serveris renderdatuga. Erinevused võivad põhjustada hüdreerimisvigu ja ettearvamatut käitumist.
Õige strateegia valimine: CSR vs. SSR
Otsus CSR-i ja SSR-i vahel ei seisne selles, kumb on universaalselt "parem", vaid selles, kumb on parem teie konkreetse rakenduse vajaduste jaoks. Raamistikud nagu Next.js ja Remix on muutnud SSR-i palju kättesaadavamaks, kuid siiski on oluline mõista kompromisse.
Millal valida kliendipoolne renderdamine (CSR):
- Väga interaktiivsed armatuurlauad ja halduspaneelid: Rakenduste puhul, mis asuvad sisselogimisseina taga, kus SEO ei ole oluline ja kasutajad on stabiilse ja kiire ühendusega, on CSR-i lihtsus sageli eelistatav.
- Sisetööriistad: Kui esimese lehe laadimise jõudlus on vähem kriitiline kui arenduskiirus ja lihtsus.
- Kontseptsioonitõestused ja MVP-d: CSR-i on tavaliselt kiirem seadistada ja juurutada, mis teeb selle ideaalseks kiireks prototüüpimiseks.
Millal valida serveripoolne renderdamine (SSR):
- Avalikud sisuveebisaidid: Blogide, uudistesaitide, turunduslehtede ja mis tahes saidi jaoks, kus otsingumootorite leitavus on esmatähtis.
- E-kaubanduse platvormid: Tooted peavad laadima kiiresti ja olema täiuslikult indekseeritavad otsingumootorite ja sotsiaalmeedia roomikute poolt, et müüki edendada.
- Globaalsele publikule suunatud rakendused: Kui teie kasutajatel võib olla aeglasem internetiühendus või vähem võimsad seadmed, parandab eelrenderdatud HTML-i saatmine oluliselt esialgset kasutajakogemust.
Väärib märkimist ka hübriidlähenemiste olemasolu, nagu Staatilise saidi genereerimine (SSG), kus lehed renderdatakse eelnevalt HTML-iks ehitamise ajal, ja Inkrementaalne staatiline regenereerimine (ISR), mis võimaldab staatilisi lehti pärast juurutamist perioodiliselt uuendada. Need pakuvad SSR-i jõudluseeliseid madalamate serverikuludega.
Kokkuvõte: mitmekülgne sild DOM-ini
react-dom pakett on palju enamat kui lihtsalt renderdamisvahend; see on keerukas teek, mis annab arendajatele peeneteralise kontrolli selle üle, kuidas nende Reacti rakendused brauseriga suhtlevad. Alates fundamentaalsest createRoot'ist kliendipoolsete rakenduste jaoks kuni võimsate utiliitideni nagu createPortal keerukate kasutajaliideste jaoks, pakub see kaasaegseks veebiarenduseks vajalikke tööriistu.
Kõige tähtsam on see, et pakkudes tugevat serveripoolset renderdamis- ja hüdreerimismehhanismi läbi react-dom/server'i ja hydrateRoot'i, annab React arendajatele võimaluse luua rakendusi, mis ei ole mitte ainult interaktiivsed ja dünaamilised, vaid ka jõudsad ja SEO-sõbralikud mitmekesisele, globaalsele publikule. Nende renderdamisstrateegiate mõistmine ja oma projekti jaoks õige valimine on osava Reacti arendaja tunnus, mis võimaldab teil pakkuda parimat võimalikku kogemust igale kasutajale, olenemata sellest, kus nad asuvad või millist seadet nad kasutavad.